from sentinelsat import SentinelAPI, read_geojson, geojson_to_wkt
import sentinelsat
from collections import OrderedDict
from pyproj import Proj, Geod, transform
from datetime import date
from decimal import Decimal
import requests
import json
try:
    from osgeo import gdal
    from osgeo import ogr
    from osgeo import osr
except ImportError:
    import gdal
    import ogr
    import osr
import zipfile
import shutil
import json
from tqdm import tqdm
import re
import os


class ShapeFile:

    def __init__(self):
        pass

    @staticmethod
    def LayerIndexToLayerName(shapefilepath, layerindex=0):
        """
        根据图层索引获取图层名称
        :param shapefilepath:
        :param layerindex:
        :return:
        """
        datasource = ogr.Open(shapefilepath)
        if layerindex:
            layer = datasource.GetLayer(layerindex)
            layername = layer.GetName()
        else:
            layer = datasource.GetLayer(0)
            layername = layer.GetName()
        datasource.Destroy()
        return layername

    @staticmethod
    def GdalOgrDataTypeToPyhtonDataType(gdalogrdatatypename, gdalogrvalue):
        """
        gdal ogr 转为python的数据类型
        :param gdalogrdatatypename:
        :param gdalogrvalue:
        :return:
        """
        if gdalogrdatatypename == "Real":
            pythonvalue = float(gdalogrvalue)
        else:
            pythonvalue = int(gdalogrvalue)
        return pythonvalue

    @staticmethod
    def GdalOgrDataTypeNameToPythonDataTypeName(gdalogrdatatypename):
        """
        由gdal ogr的数据类型转换为python的数据类型名
        :param gdalogrdatatypename:
        :return:
        """
        if gdalogrdatatypename == "Real":
            pythondatatypename = "float"
        else:
            pythondatatypename = "int"
        return pythondatatypename

    @staticmethod
    def GetFieldDataType(shapefilepath, layername, fieldname):
        """
        获取shape file 的指定字段数据类型
        :param shapefilepath:
        :param layername:
        :param fieldname:
        :return:
        """
        datasource = ogr.Open(shapefilepath)
        if layername:
            layer = datasource.GetLayerByName(layername)
        else:
            layer = datasource.GetLayer(0)
        featuredefn = layer.GetLayerDefn()
        fieldindex = featuredefn.GetFieldIndex(fieldname)
        fielddefn = featuredefn.GetFieldDefn(fieldindex)
        datatype = fielddefn.GetType()
        datatypename = fielddefn.GetTypeName()
        datasource.Destroy()
        return datatypename

    @staticmethod
    def OpenGDBFile(gdbfilepath):
        # driver = ogr.GetDriverByName("File GDB")
        # gdbdriver = ogr.GetDriverByName("FileGDB")
        datasource = ogr.Open(gdbfilepath)
        driver = datasource.GetDriver()
        drivername = driver.GetName()
        print(drivername)
        layercount = datasource.GetLayerCount()
        for layerindex in range(layercount):
            layer = datasource.GetLayer(layerindex)
            layername = layer.GetName()
            print(layername)
        return

    @staticmethod
    def GetShapeFileSpatialreferencesystemWkt(shapefilepath, layername=None):
        """
        导出shape file 的空间参考系为proj 的json格式
        :param shapefilepath:
        :param layername:
        :return:
        """
        datasource = ogr.Open(shapefilepath)
        if layername:
            layer = datasource.GetLayerByName(layername)
        else:
            layer = datasource.GetLayer(0)
        spatialreferencesystem = layer.GetSpatialRef()
        spatialreferencesystemwkt = spatialreferencesystem.ExportToWkt()
        datasource.Destroy()
        return spatialreferencesystemwkt

    @staticmethod
    def GetShapeFileSpatialreferencesystemProjJson(shapefilepath, layername=None):
        """
        导出shape file 的空间参考系为proj 的json格式
        :param shapefilepath:
        :param layername:
        :return:
        """
        datasource = ogr.Open(shapefilepath)
        if layername:
            layer = datasource.GetLayerByName(layername)
        else:
            layer = datasource.GetLayer(0)
        spatialreferencesystem = layer.GetSpatialRef()
        spatialreferencesystemprojjson = spatialreferencesystem.ExportToPROJJSON()
        datasource.Destroy()
        return spatialreferencesystemprojjson

    @staticmethod
    def GetShapeFileSpatialreferencesystemProj4(shapefilepath, layername=None):
        """
        导出shape file 的空间参考系为proj 的json格式
        :param shapefilepath:
        :param layername:
        :return:
        """
        datasource = ogr.Open(shapefilepath)
        if layername:
            layer = datasource.GetLayerByName(layername)
        else:
            layer = datasource.GetLayer(0)
        spatialreferencesystem = layer.GetSpatialRef()
        spatialreferencesystemproj4 = spatialreferencesystem.ExportToProj4()
        datasource.Destroy()
        return spatialreferencesystemproj4

    @staticmethod
    def GetShapeFileLayerCount(shapefilepath):
        """
        获取shape file 的layer 数量
        :param shapefilepath:
        :return:
        """
        datasource = ogr.Open(shapefilepath)
        layercount = datasource.GetLayerCount()
        datasource.Destroy()
        return layercount

    @staticmethod
    def GetShapeFileFeatureDictList(shapefilepath, layername=None, fieldNameList=None):
        """
        获得shp file 要素字典列表
        :param shapefilepath:
        :param layername:
        :param fieldNameList:
        :return:
        """
        gdal.SetConfigOption("SHAPE_ENCODING", "GBK")
        datasource = ogr.Open(shapefilepath)
        if layername:
            layer = datasource.GetLayerByName(layername)
        else:
            layer = datasource.GetLayer(0)
        featureCount = layer.GetFeatureCount()
        featuredictlist = []
        if fieldNameList is None:
            for featureindex in range(featureCount):
                feature = layer.GetFeature(featureindex)
                featurejson = feature.ExportToJson()
                featuredict = json.loads(featurejson)
                featuredictlist.append(featuredict)
                feature.Destroy()
        else:
            for featureIndex in range(featureCount):
                feature = layer.GetFeature(featureIndex)
                featurejson = feature.ExportToJson()
                featuredict = json.loads(featurejson)
                propertiesDict = {}
                for fieldName in fieldNameList:
                    propertiesDict[fieldName] = featuredict["properties"][fieldName]
                featuredict["properties"] = propertiesDict
                featuredictlist.append(featuredict)
                feature.Destroy()
        datasource.Destroy()
        return featuredictlist

    @staticmethod
    def GetShapeFileLayerNameList(shapefilepath):
        """
        获取shape file 的 layername list表
        :param shapefilepath:
        :return:
        """
        datasource = ogr.Open(shapefilepath)
        layercount = datasource.GetLayerCount()
        layernamelist = []
        for layerindex in range(layercount):
            layer = datasource.GetLayer(layerindex)
            layername = layer.GetName()
            layernamelist.append(layername)
        datasource.Destroy()
        return layernamelist

    @staticmethod
    def CreateEmptyShapeFile(
            shapefilePath,
            layername,
            spatialreferencesystemprojjson,
            geometrytype):
        """
        生成空的shp file的指定shape
        :param shapefilePath:
        :param layername:
        :param spatialreferencesystemprojjson:
        :param geometrytype:
        :return:
        """
        if not os.path.exists(shapefilePath):
            drivername = "ESRI Shapefile"
            driver = ogr.GetDriverByName(drivername)
            datasource = driver.CreateDataSource(shapefilePath)
        else:
            datasource = ogr.Open(shapefilePath, 1)
        spatialreferencesystem = osr.SpatialReference()
        spatialreferencesystem.ImportFromProj4(spatialreferencesystemprojjson)
        layercount = datasource.GetLayerCount()
        layernamelist = []
        for layerindex in range(layercount):
            layer = datasource.GetLayer(layerindex)
            if layer.GetName() == layername:
                print("该图层存在，创建失败！")
                return
        layer = datasource.CreateLayer(layername, srs=spatialreferencesystem, geom_type=geometrytype)
        datasource.Destroy()
        return

    @staticmethod
    def GetShapeFileGeometrytype(shapefilepath, layername=None):
        """
        获得shp file 的几何类型
        :param shapefilepath:
        :param layername:
        :return:
        """
        datasource = ogr.Open(shapefilepath)
        if layername:
            layer = datasource.GetLayerByName(layername)
        else:
            layer = datasource.GetLayer(0)
        geometrytype = layer.GetGeomType()
        datasource.Destroy()
        return geometrytype

    @staticmethod
    def GetShapeFileFieldList(shapefilepath, layername=None):
        """
        获取shp file 字段定义列表
        :param shapefilepath:
        :param layername:
        :return:
        """
        datasource = ogr.Open(shapefilepath)
        if layername:
            layer = datasource.GetLayerByName(layername)
        else:
            layer = datasource.GetLayer(0)
        featuredefn = layer.GetLayerDefn()
        fieldcount = featuredefn.GetFieldCount()
        fielddictlist = []
        for fieldindex in range(fieldcount):
            fielddefn = featuredefn.GetFieldDefn(fieldindex)
            fielddict = {
                "name": fielddefn.name,
                "type": fielddefn.type,
                "width": fielddefn.width,
                "justify": fielddefn.justify,
                "precision": fielddefn.precision}
            fielddictlist.append(fielddict)
        datasource.Destroy()
        return fielddictlist

    @staticmethod
    def GetSpatialReferenceSystemType(shapefilepath, layername=None):
        datasource = ogr.Open(shapefilepath)
        if layername:
            layer = datasource.GetLayerByName(layername)
        else:
            layer = datasource.GetLayer(0)
        spatialreferencesystem = layer.GetSpatialRef()
        if spatialreferencesystem.IsGeographic():
            spatialreferencesystemname = spatialreferencesystem.GetName()
            print("投影坐标系", "坐标系名称为：", spatialreferencesystemname)
        elif spatialreferencesystem.IsProjected():
            spatialreferencesystemname = spatialreferencesystem.GetName()
            print("地理坐标系", "坐标系名称为：", spatialreferencesystemname)
        else:
            print("非坐标系")
        datasource.Destroy()
        return

    @staticmethod
    def GetShapeFileFeatureDictByField(fieldDict, shapeFilePath, layerName=None):
        """
        依据字段获取要素字典
        :param fieldDict:
        :param shapeFilePath:
        :param layerName:
        :return:
        """
        datasource = ogr.Open(shapeFilePath)
        if layerName:
            layer = datasource.GetLayerByName(layerName)
        else:
            layer = datasource.GetLayer(0)
        fieldName = list(fieldDict.keys())[0]
        fieldValue = fieldDict[fieldName]
        layer.SetAttributeFilter("%s='%s'" % (fieldName, fieldValue))
        featureDictList = []
        feature = layer.GetNextFeature()
        while feature is not None:
            featureJson = feature.ExportToJson()
            featureDict = json.loads(featureJson)
            featureDictList.append(featureDict)
            feature = layer.GetNextFeature()
        layer.ResetReading()
        datasource.Destroy()
        return featureDictList

    @staticmethod
    def FeatureDictListSpatialreferencesystemProjectTransformGeography(
            projectFeatureDictList,
            projectSpatialReferenceSystemWkt,
            geographySpatialReferenceSystemWkt):
        """
        转换要素列表几何坐标（投影转地理）
        :param projectFeatureDictList:
        :param projectSpatialReferenceSystemWkt:
        :param geographySpatialReferenceSystemWkt:
        :return:
        """
        osrprojectSpatialReferenceSystem = osr.SpatialReference()
        osrprojectSpatialReferenceSystem.ImportFromWkt(projectSpatialReferenceSystemWkt)
        projectSpatialReferenceSystemProj4 = osrprojectSpatialReferenceSystem.ExportToProj4()
        osrgeographySpatialReferenceSystem = osr.SpatialReference()
        osrgeographySpatialReferenceSystem.ImportFromWkt(geographySpatialReferenceSystemWkt)
        geographySpatialReferenceSystemProj4 = osrgeographySpatialReferenceSystem.ExportToProj4()
        proj4projectSpatialReferenceSystem = Proj(projectSpatialReferenceSystemProj4)
        geographyFeatureDictList = []
        for projectFeatureDict in projectFeatureDictList:
            geographyFeatureDict = projectFeatureDict
            geometrydict = projectFeatureDict["geometry"]
            geometrytype = geometrydict["type"]
            if geometrytype == "Polygon":
                polygon = geometrydict["coordinates"]
                newpolygon = []
                for ring in polygon:
                    newring = []
                    for point in ring:
                        x1, y1 = proj4projectSpatialReferenceSystem(point[0], point[1], inverse=True)
                        newpoint = [x1, y1]
                        newring.append(newpoint)
                    newpolygon.append(newring)
                geographyFeatureDict["geometry"]["coordinates"] = newpolygon
                geographyFeatureDictList.append(geographyFeatureDict)
            elif geometrytype == "MultiPolygon":
                fielddictlist = projectFeatureDict["properties"]
                polygonlist = geometrydict["coordinates"]
                newpolygonlist = []
                for polygon in polygonlist:
                    newpolygon = []
                    for ring in polygon:
                        newring = []
                        for point in ring:
                            x1, y1 = proj4projectSpatialReferenceSystem(point[0], point[1], inverse=True)
                            newpoint = [x1, y1]
                            newring.append(newpoint)
                        newpolygon.append(newring)
                    newpolygonlist.append(newpolygon)
                geographyFeatureDict["geometry"]["coordinates"] = newpolygonlist
                geographyFeatureDictList.append(geographyFeatureDict)
            elif geometrytype == "Point":
                print(geometrytype)
            else:
                print("error!")
        return geographyFeatureDictList

    @staticmethod
    def FeatureDictListSpatialreferenceSystemGeographyTransformProject(
            geographyFeatureDictList,
            geographySpatialReferenceSystemWkt,
            projectSpatialreferenceSystemWkt):
        """
        转换要素列表几何坐标（地理转投影）
        :param geographyFeatureDictList:
        :param geographySpatialReferenceSystemWkt:
        :param projectSpatialreferenceSystemWkt:
        :return:
        """
        geographySpatialReferenceSystem = osr.SpatialReference()
        geographySpatialReferenceSystem.ImportFromWkt(geographySpatialReferenceSystemWkt)
        projectSpatialReferenceSystem = osr.SpatialReference()
        projectSpatialReferenceSystem.ImportFromWkt(projectSpatialreferenceSystemWkt)
        coordinatetransformation = osr.CoordinateTransformation(
            geographySpatialReferenceSystem, projectSpatialReferenceSystem)
        projectFeatureDictList = []
        for geographyFeatureDict in geographyFeatureDictList:
            projectFeatureDict = geographyFeatureDict
            geometrydict = geographyFeatureDict["geometry"]
            geometrytype = geometrydict["type"]
            if geometrytype == "Polygon":
                polygon = geometrydict["coordinates"]
                newpolygon = []
                for ring in polygon:
                    newring = []
                    for point in ring:
                        pointtuple = coordinatetransformation.TransformPoint(point[1], point[0])
                        newpoint = [pointtuple[0], pointtuple[1]]
                        newring.append(newpoint)
                    newpolygon.append(newring)
                projectFeatureDict["geometry"]["coordinates"] = newpolygon
                projectFeatureDictList.append(projectFeatureDict)
            elif geometrytype == "MultiPolygon":
                fielddictlist = geographyFeatureDict["properties"]
                polygonlist = geometrydict["coordinates"]
                newpolygonlist = []
                for polygon in polygonlist:
                    newpolygon = []
                    for ring in polygon:
                        newring = []
                        for point in ring:
                            pointtuple = coordinatetransformation.TransformPoint(point[1], point[0])
                            newpoint = [pointtuple[0], pointtuple[1]]
                            newring.append(newpoint)
                        newpolygon.append(newring)
                    newpolygonlist.append(newpolygon)
                projectFeatureDict["geometry"]["coordinates"] = newpolygonlist
                projectFeatureDictList.append(projectFeatureDict)
            elif geometrytype == "Point":
                print(geometrytype)
            else:
                print("error!")
        return projectFeatureDictList

    @staticmethod
    def FieldDictListUpdateShapeFile(
            fielddictlist,
            shapefilepath,
            layername=None):
        """
        依据
        :param fielddictlist:
        :param shapefilepath:
        :param layername:
        :return:
        """
        datasource = ogr.Open(shapefilepath, 1)
        if layername:
            layer = datasource.GetLayerByName(layername)
        else:
            layer = datasource.GetLayer(0)
        featureDefn = layer.GetLayerDefn()
        for fielddict in fielddictlist:
            fieldName = fielddict["name"]
            fieldIndex = featureDefn.GetFieldIndex(fieldName)
            if fieldIndex < 0:
                field = ogr.FieldDefn()
                field.name = fielddict["name"]
                field.type = fielddict["type"]
                field.width = fielddict["width"]
                field.justify = fielddict["justify"]
                field.precision = fielddict["precision"]
                layer.CreateField(field)
                field.Destroy()
        datasource.Destroy()
        return

    @staticmethod
    def FeatureDictListUpdateShapeFile(
            featuredictlist,
            shapefilepath,
            layername=None):
        """
        根据要素字典列表更新shp file
        :param featuredictlist:
        :param shapefilepath:
        :param layername:
        :return:
        """
        # gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8")
        gdal.SetConfigOption("SHAPE_ENCODING", "GBK")
        # gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")
        datasource = ogr.Open(shapefilepath, 1)
        if layername:
            layer = datasource.GetLayerByName(layername)
        else:
            layer = datasource.GetLayer(0)
        layerdefn = layer.GetLayerDefn()
        fieldcount = layerdefn.GetFieldCount()
        for featuredict in featuredictlist:
            feature = ogr.Feature(layerdefn)
            fielddict = featuredict["properties"]
            for key, value in fielddict.items():
                feature.SetField(key, value)
            geometrydict = featuredict["geometry"]
            geometryjson = json.dumps(geometrydict)
            geometry = ogr.CreateGeometryFromJson(geometryjson)
            feature.SetGeometry(geometry)
            layer.CreateFeature(feature)
        datasource.Destroy()
        return

    @staticmethod
    def LayerIntersect(
            firstshapefilepath,
            firstlayername,
            secondshapefilepath,
            secondlayername):
        """
        求两个图层中相交的要素
        :param firstshapefilepath:
        :param firstlayername:
        :param secondshapefilepath:
        :param secondlayername:
        :return:
        """
        firstdatasource = ogr.Open(firstshapefilepath)
        firstlayer = firstdatasource.GetLayerByName(firstlayername)
        firstfeaturecount = firstlayer.GetFeatureCount()
        seconddatasource = ogr.Open(secondshapefilepath)
        secondlayer = seconddatasource.GetLayerByName(secondlayername)
        secondfeaturecount = secondlayer.GetFeatureCount()
        countysentinel2featuredictlist = []
        for firstfeatureindex in tqdm(range(firstfeaturecount)):
            firstfeature = firstlayer.GetFeature(firstfeatureindex)
            firstgeometry = firstfeature.geometry()
            for secondfeatureindex in range(secondfeaturecount):
                secondfeature = secondlayer.GetFeature(secondfeatureindex)
                secondgeometry = secondfeature.geometry()
                if firstgeometry.Intersect(secondgeometry):
                    firstfeaturejson = firstfeature.ExportToJson()
                    firstfeaturedict = json.loads(firstfeaturejson)
                    countysentinel2featuredictlist.append(firstfeaturedict)
                    break
        firstdatasource.Destroy()
        seconddatasource.Destroy()
        return countysentinel2featuredictlist


class RasterFile:

    def __init__(self):
        pass

    @staticmethod
    def GetRasterFileDataType(rasterfilepath):
        """
        获取栅格波段数据类型，并返GDAL数据类型对象
        :param rasterfilepath:
        :return:
        """
        raster = gdal.Open(rasterfilepath, 0)
        firstband = raster.GetRasterBand(1)
        datatype = firstband.DataType
        del raster
        return datatype

    @staticmethod
    def GetRasterFileNoDataValue(rasterfilepath):
        raster = gdal.Open(rasterfilepath, 0)
        firstband = raster.GetRasterBand(1)
        nodatavalue = firstband.GetNoDataValue()
        del raster
        return nodatavalue

    @staticmethod
    def GetRasterFileSpatialreferencesystemwkt(rasterfilepath):
        raster = gdal.Open(rasterfilepath)
        spatialreferencesystem = raster.GetSpatialRef()
        spatialreferencesystemwkt = spatialreferencesystem.ExportToWkt()
        del raster
        return spatialreferencesystemwkt

    @staticmethod
    def GetRasterFileGeoTransform(rasterfilepath):
        """
        获取栅格仿射参数，并返回元组
        :param rasterfilepath:
        :return:
        """
        raster = gdal.Open(rasterfilepath, 0)
        geotransform = raster.GetGeoTransform()
        del raster
        return geotransform

    @staticmethod
    def GetRasterFileProjection(rasterfilepath):
        """
        获取栅格投影信息，并返回字符串
        :param rasterfilepath:
        :return:
        """
        raster = gdal.Open(rasterfilepath, 0)
        project = raster.GetProjection()
        del raster
        return project

    @staticmethod
    def GetRasterFileShape(rasterfilepath):
        """
        获取栅格大小
        :param rasterfilepath:
        :return:
        """
        raster = gdal.Open(rasterfilepath)
        width, height, bandcount = raster.RasterXSize, raster.RasterYSize, raster.RasterCount
        shape = [width, height, bandcount]
        del raster
        return shape

    @staticmethod
    def PythonDataTypeNameToGdalDataTypeName(pythondatatypename):
        """
        由python的数据类型的名称获得gdal数据类型名称
        :param pythondatatypename:
        :return:
        """
        if pythondatatypename == "int":
            gdaldatatypename = "UInt16"
        elif pythondatatypename == "float":
            gdaldatatypename = "Float32"
        else:
            gdaldatatypename = "Byte"
        return gdaldatatypename

    @staticmethod
    def PythonDataTypeNameToGdalDataType(pythondatatypename):
        """
        由python数据类型名称获得gdal数据类型对象
        :param pythondatatypename:
        :return:
        """
        if pythondatatypename == "int":
            return gdal.GDT_UInt16
        elif pythondatatypename == "float":
            return gdal.GDT_Float32
        else:
            return gdal.GDT_Unknown


def ShapeFileSpatialConnectivity(
        firstShapeFilePath,
        firstLayerName,
        secondShapeFilePath,
        secondeLayerName):
    """
    空间连接shape file
    :param firstShapeFilePath:
    :param firstLayerName:
    :param secondShapeFilePath:
    :param secondeLayerName:
    :return:
    """
    firstFieldName = "S2Zone"
    firstdatasource = ogr.Open(firstShapeFilePath, 1)
    firstlayer = firstdatasource.GetLayerByName(firstLayerName)
    firstfeaturecount = firstlayer.GetFeatureCount()
    firstFeatureDefn = firstlayer.GetLayerDefn()
    fieldIndex = firstFeatureDefn.GetFieldIndex(firstFieldName)
    firstFieldDefn = firstFeatureDefn.GetFieldDefn(fieldIndex)
    firstFieldNameRef = firstFieldDefn.GetNameRef()
    seconddatasource = ogr.Open(secondShapeFilePath)
    secondlayer = seconddatasource.GetLayerByName(secondeLayerName)
    secondfeaturecount = secondlayer.GetFeatureCount()
    for firstfeatureindex in tqdm(range(firstfeaturecount)):
        firstfeature = firstlayer.GetFeature(firstfeatureindex)
        firstgeometry = firstfeature.geometry()
        firstfeaturejson = firstfeature.ExportToJson()
        firstfeaturedict = json.loads(firstfeaturejson)
        sentinel2ZoneList = []
        for secondfeatureindex in range(secondfeaturecount):
            secondfeature = secondlayer.GetFeature(secondfeatureindex)
            secondgeometry = secondfeature.geometry()
            if firstgeometry.Intersect(secondgeometry):
                secondfeaturejson = secondfeature.ExportToJson()
                secondfeaturedict = json.loads(secondfeaturejson)
                secondfieldDict = secondfeaturedict["properties"]
                sentinel2ZoneStr = secondfieldDict['GZD'] + secondfieldDict['kmSQ_ID']
                sentinel2ZoneList.append(sentinel2ZoneStr)
        s2zoneFieldValue = "_".join(sentinel2ZoneList)
        firstfeature.SetField2(firstFieldNameRef, s2zoneFieldValue)
        firstlayer.SetFeature(firstfeature)
    firstdatasource.Destroy()
    seconddatasource.Destroy()
    return


def ConfigJsonFile():
    currentFolderPath = os.getcwd()
    configJsonFilePath = currentFolderPath + r"s2zoneconfig.json"
    configdict = {
        "shapeFilePath": r"E:\localhosttestdata\hebeixianyu",
        "saveFolderPath": r"E:\localhosttestdata",
        "producttype": "S2MSI2A",
        "maxcloudcoverpercentage": 30
    }
    with open(configJsonFilePath, "w") as jsonfile:
        configjsonstr = json.dumps(configdict, indent=4)
        jsonfile.write(configjsonstr)
    return


def FindAllFile(infolder):
    """寻找该目录下的所有文件"""
    names = os.listdir(infolder)
    filepaths = []
    for name in names:
        unkownfilefolder = os.path.join(infolder, name)
        if os.path.isfile(unkownfilefolder):
            filepaths.append(unkownfilefolder)
        elif os.path.isdir(unkownfilefolder):
            filepaths = filepaths + FindAllFile(unkownfilefolder)
    return filepaths


def GetGoalFile(infolder, sign=None):
    """
    搜索获得目标文件路径集
    :param infolder: 搜索的目标文件夹路径
    :param sign: 文件名所包含的字符串
    :return:
    """
    if sign is None:
        return cls.FindAllFile(infolder)
    elif sign[0] == r".":
        filepaths = FindAllFile(infolder)
        rasfilepaths = [
            filepath
            for filepath in filepaths
            if os.path.splitext(os.path.split(filepath)[1])[1] == sign]
        return rasfilepaths
    else:
        filepaths = FindAllFile(infolder)
        rasfilepaths = [
            filepath
            for filepath in filepaths
            if os.path.splitext(os.path.split(filepath)[1])[0] == sign]
        return rasfilepaths


def ShapeFileGeographyTransformProject(
        projectSpatialReferenceSystemWkt,
        geographySpatialReferenceSystemShapeFilePath,
        geographySpatialReferenceSystemLayerName,
        projectSpatialReferenceSystemShapeFilePath,
        projectSpatialReferenceSystemLayerName):
    """
    shape file 空间参考系转换（地理转投影）
    :param projectSpatialReferenceSystemWkt:
    :param geographySpatialReferenceSystemShapeFilePath:
    :param geographySpatialReferenceSystemLayerName:
    :param projectSpatialReferenceSystemShapeFilePath:
    :param projectSpatialReferenceSystemLayerName:
    :return:
    """
    geographySpatialReferenceSystemWkt = ShapeFile.GetShapeFileSpatialreferencesystemWkt(
        geographySpatialReferenceSystemShapeFilePath, geographySpatialReferenceSystemLayerName)
    geogmetryType = ShapeFile.GetShapeFileGeometrytype(
        geographySpatialReferenceSystemShapeFilePath, geographySpatialReferenceSystemLayerName)
    ShapeFile.CreateEmptyShapeFile(
        projectSpatialReferenceSystemShapeFilePath,
        projectSpatialReferenceSystemLayerName,
        projectSpatialReferenceSystemWkt,
        geogmetryType)
    fieldDictList = ShapeFile.GetShapeFileFieldList(
        geographySpatialReferenceSystemShapeFilePath, geographySpatialReferenceSystemLayerName)
    geographyFeatureDictList = ShapeFile.GetShapeFileFeatureDictList(
        geographySpatialReferenceSystemShapeFilePath, geographySpatialReferenceSystemLayerName)
    ShapeFile.FieldDictListUpdateShapeFile(
        fieldDictList, projectSpatialReferenceSystemShapeFilePath, projectSpatialReferenceSystemLayerName)
    projectFeatureDictList = ShapeFile.FeatureDictListSpatialreferenceSystemGeographyTransformProject(
        geographyFeatureDictList, geographySpatialReferenceSystemWkt, projectSpatialReferenceSystemWkt)
    ShapeFile.FeatureDictListUpdateShapeFile(
        projectFeatureDictList, projectSpatialReferenceSystemShapeFilePath, projectSpatialReferenceSystemLayerName)
    return


def ShapeFileProjectTransformGeography(
        geographySpatialReferenceSystemWkt,
        projectSpatialReferenceSystemShapeFilePath,
        projectSpatialReferenceSystemLayerName,
        geographySpatialReferenceSystemShapeFilePath,
        geographySpatialReferenceSystemLayerName):
    """
    shape file 空间参考系转换（投影转地理）
    :param geographySpatialReferenceSystemWkt:
    :param projectSpatialReferenceSystemShapeFilePath:
    :param projectSpatialReferenceSystemLayerName:
    :param geographySpatialReferenceSystemShapeFilePath:
    :param geographySpatialReferenceSystemLayerName:
    :return:
    """
    projectSpatialReferenceSystemWkt = ShapeFile.GetShapeFileSpatialreferencesystemWkt(
        projectSpatialReferenceSystemShapeFilePath,
        projectSpatialReferenceSystemLayerName)
    geogmetryType = ShapeFile.GetShapeFileGeometrytype(
        projectSpatialReferenceSystemShapeFilePath,
        projectSpatialReferenceSystemLayerName)
    ShapeFile.CreateEmptyShapeFile(
        geographySpatialReferenceSystemShapeFilePath,
        geographySpatialReferenceSystemLayerName,
        geographySpatialReferenceSystemWkt,
        geogmetryType)
    fieldDictList = ShapeFile.GetShapeFileFieldList(
        projectSpatialReferenceSystemShapeFilePath,
        projectSpatialReferenceSystemLayerName)
    projectFeatureDictList = ShapeFile.GetShapeFileFeatureDictList(
        projectSpatialReferenceSystemShapeFilePath,
        projectSpatialReferenceSystemLayerName)
    ShapeFile.FieldDictListUpdateShapeFile(
        fieldDictList,
        geographySpatialReferenceSystemShapeFilePath,
        geographySpatialReferenceSystemLayerName)
    geographyFeatureDictList = ShapeFile.FeatureDictListSpatialreferencesystemProjectTransformGeography(
        projectFeatureDictList,
        projectSpatialReferenceSystemWkt,
        geographySpatialReferenceSystemWkt)
    ShapeFile.FeatureDictListUpdateShapeFile(
        geographyFeatureDictList,
        geographySpatialReferenceSystemShapeFilePath,
        geographySpatialReferenceSystemLayerName)
    return


class DownloadSentinel2:

    def __init__(self):
        pass

    @staticmethod
    def GetEsaWebApi(username=None, password=None, url=None):
        """
        下载sentinel2
        :param url:
        :param password:
        :param username:
        :return:
        """
        if username is None:
            username = "liangjiahao"
        if password is None:
            password = "liangjiahao"
        api = None
        if url is None:
            url = "https://scihub.copernicus.eu/dhus"
            api = sentinelsat.SentinelAPI(
                username,
                password,
                api_url=url,
                show_progressbars=True,
                timeout=None)
        else:
            apiurl = "https://scihub.copernicus.eu/apihub/"
            api = sentinelsat.SentinelAPI(
                username,
                password,
                api_url=apiurl,
                show_progressbars=True,
                timeout=None)
        return api

    @staticmethod
    def CheckProductByMGRS(api, sentinel2ZoneList, kwargs=None):
        """
        依据图幅编号下载影像
        :param kwargs:
        :param api:
        :param sentinel2ZoneList:
        :return:
        """
        if kwargs is None:
            kwargs = {
                "date": ('NOW-30DAYS', 'NOW'),
                "platformname": 'Sentinel-2',
                "producttype": "S2MSI2A",  # S2MSI1C
                "cloudcoverpercentage": (0, 30)}
        productAllOrderdDict = OrderedDict()
        for sentinel2Zone in sentinel2ZoneList:
            filename = "*_T%s_*" % sentinel2Zone
            productSingleOrderDict = api.query(
                filename=filename,
                date=kwargs["date"],
                platformname=kwargs["platformname"],
                producttype=kwargs["producttype"],
                cloudcoverpercentage=kwargs["cloudcoverpercentage"])
            productAllOrderdDict.update(productSingleOrderDict)
        return productAllOrderdDict

    @staticmethod
    def CheckProductByFileName(api, fileNameList, kwargs=None):
        """
        依据图幅编号下载影像
        :param kwargs:
        :param api:
        :param fileNameList:
        :return:
        """
        if kwargs is None:
            kwargs = {
                "date": ('NOW-30DAYS', 'NOW'),
                "platformname": 'Sentinel-2',
                "producttype": "S2MSI2A",  # S2MSI1C
                "cloudcoverpercentage": (0, 30)}
        productAllOrderdDict = OrderedDict()
        for fileName in fileNameList:
            productSingleOrderDict = api.query(
                filename=fileName,
                date=kwargs["date"],
                platformname=kwargs["platformname"],
                producttype=kwargs["producttype"],
                cloudcoverpercentage=kwargs["cloudcoverpercentage"])
            productAllOrderdDict.update(productSingleOrderDict)
        return productAllOrderdDict

    @staticmethod
    def GetProductInfo(api, productAllOrderdDict, saveFolderPath):
        """
        获得产品信息
        :param api:
        :param productAllOrderdDict:
        :param saveFolderPath:
        :return:
        """
        productInfoDictList = []
        for product in productAllOrderdDict:
            productInfoDict = api.get_product_odata(product)
            productName = productInfoDict['title']
            print("Product name:", productName)
            productUrl = productInfoDict['url']
            print("   Product url:", productUrl)
            productDate = productInfoDict['date']
            print("   Product date:", productDate)
            productSize = productInfoDict['size']
            print("   Product size:", productSize)
            productID = productInfoDict['id']
            print("   Product ID:", productID)
            productMd5 = productInfoDict['md5']
            print("   Product md5:", productMd5)
            productOnline = productInfoDict['Online']
            print("   Product Online:", productOnline)
            productCreationDate = productInfoDict['Creation Date']
            print("   Product Creation Date:", productCreationDate)
            productIngestionDate = productInfoDict['Ingestion Date']
            print("   Product Ingestion Date:", productIngestionDate)
            productInfoDictList.append(productInfoDict)
        return productInfoDictList

    @staticmethod
    def DownloadProductInfoQuickImage(productInfoDictList, saveFolderPath, username=None, password=None):
        """
        下载快图
        :param productInfoDictList:
        :param saveFolderPath:
        :param username:
        :param password:
        :return:
        """
        if username is None:
            username = "liangjiahao"
        if password is None:
            password = "liangjiahao"
        for productInfoDict in productInfoDictList:
            productName = productInfoDict['title']
            jpgname = productName + r'.jpg'
            productUrl = productInfoDict['url']
            qlookUrl = productUrl[0:(-len('$value'))] + "Products('Quicklook')/$value"
            response = requests.get(qlookUrl, stream=True, auth=(username, password))  # 需要设置登录信息,否则status_code为401 401错误表示的是被请求的页面需要用户名和密码
            if response.status_code == 200:
                jpgFilePath = os.path.join(saveFolderPath, jpgname)
                with open(jpgFilePath, 'wb') as file:
                    for data in response.iter_content(128):
                        file.write(data)
            else:
                print(jpgname + ' 快视图下载失败')
        return

    @staticmethod
    def FromFolderSelectS2ZoneNoneList(folderPath):
        directoryNameList = os.listdir(folderPath)
        partten = re.compile(".*\.jpg")
        fileNameList = []
        for directoryName in dirextoryNameList:
            if partten.search(directoryName):
                fileNameList.append(directoryName)
        return fileNameList

    @staticmethod
    def DownloadMultipleProduct(api, productList):
        print("共%d景影像开始下载:" % len(productList))
        for listIndex, product in enumerate(productList):
            print("正在下载(%d/%d)")
            productInfoDict = api.get_product_odata(product)
            productName = productInfoDict['title']
            print("Product name:", productName)
            productDate = productInfoDict['date']
            print("Product date:", productDate)
            productSize = productInfoDict['size']
            print("Product size:", productSize)
            api.download(product)
        return

    @staticmethod
    def GeoJsonDownLoad(api, footprint, date, producttype, cloudcover):
        # 通过设置OpenSearch API查询参数筛选符合条件的所有Sentinel-2 L2A级数据
        products = api.query(footprint,  # Area范围
                             date=date,  # 搜索的日期范围
                             platformname='Sentinel-2',  # 卫星平台名，Sentinel-2
                             producttype=producttype,  # 产品数据等级，‘S2MSI2A’表示S2-L2A级产品
                             cloudcoverpercentage=cloudcover)  # 云量百分比
        return products

    @staticmethod
    def GetGeographyWorldSentinel2ShapeFile(
            geographyShapeFilePath,
            geographyLayerName,
            projectWolrdSentinel2ShapeFilePath,
            geographyWorldSentinel2ShapeFilePath):
        """
        获得地理的世界哨兵图幅矢量
        :param geographyShapeFilePath:
        :param geographyLayerName:
        :param projectWolrdSentinel2ShapeFilePath:
        :param geographyWorldSentinel2ShapeFilePath:
        :return:
        """
        geographySpatialReferenceSystemWkt = ShapeFile.GetShapeFileSpatialreferencesystemWkt(
            geographyShapeFilePath, geographyLayerName)
        layerNameList = ShapeFile.GetShapeFileLayerNameList(projectWolrdSentinel2ShapeFilePath)
        for layerName in layerNameList:
            ShapeFileProjectTransformGeography(
                geographySpatialReferenceSystemWkt,
                projectWolrdSentinel2ShapeFilePath,
                layerName,
                geographyWorldSentinel2ShapeFilePath,
                layerName)
        return

    @staticmethod
    def CountySentinel2ZoneShapeFile(
            countyShapeFilePath,
            singleLayerShapeFilePath):
        """
        构造新的县区shp file
        :param countyShapeFilePath:
        :param singleLayerShapeFilePath:
        :return:
        """
        addfileDictList = [{"name": "S2Zone", "type": 4, "width": 100, "justify": 0, "precision": 0}]
        ShapeFile.FieldDictListUpdateShapeFile(addfileDictList, countyShapeFilePath)
        countyLayerName = ShapeFile.LayerIndexToLayerName(countyShapeFilePath, 0)
        singleLayerName = ShapeFile.LayerIndexToLayerName(singleLayerShapeFilePath, 0)
        ShapeFileSpatialConnectivity(
            countyShapeFilePath,
            countyLayerName,
            singleLayerShapeFilePath,
            singleLayerName)
        return

    @staticmethod
    def ComposeSingleLayerShapeFile(
            multipleLayerShapeFilePath,
            singleLayerShapeFilePath,
            singleLayerName,
            fieldNameList=None):
        """
        全世界哨兵图幅多图层shp file转为单图层shp file
        :param multipleLayerShapeFilePath:
        :param singleLayerShapeFilePath:
        :param singleLayerName:
        :param fieldNameList:
        :return:
        """
        layerNameList = ShapeFile.GetShapeFileLayerNameList(multipleLayerShapeFilePath)
        effectiveLayerNameList = []
        for layerName in layerNameList[:-3]:
            layerNameStrList = layerName.split("_")
            sheetNumber = layerNameStrList[-1][:2]
            if 1 < int(sheetNumber) < 60:
                effectiveLayerNameList.append(layerName)
        geogmetryType = ShapeFile.GetShapeFileGeometrytype(multipleLayerShapeFilePath)
        spatialReferenceSystemWkt = ShapeFile.GetShapeFileSpatialreferencesystemWkt(multipleLayerShapeFilePath)
        fieldDictList = ShapeFile.GetShapeFileFieldList(multipleLayerShapeFilePath)
        if fieldNameList is None:
            fieldNameList = ["GZD", "kmSQ_ID"]
        newFieldDictList = []
        for fieldDict in fieldDictList:
            if fieldDict["name"] in fieldNameList:
                newFieldDictList.append(fieldDict)
        projectFeatureDictList = []
        for effectiveLayerName in effectiveLayerNameList:
            FeatureDictList = ShapeFile.GetShapeFileFeatureDictList(
                multipleLayerShapeFilePath,
                effectiveLayerName,
                fieldNameList=fieldNameList)
            projectFeatureDictList = projectFeatureDictList + FeatureDictList
        ShapeFile.CreateEmptyShapeFile(
            singleLayerShapeFilePath,
            singleLayerName,
            spatialReferenceSystemWkt,
            geogmetryType)
        ShapeFile.FieldDictListUpdateShapeFile(
            newFieldDictList,
            singleLayerShapeFilePath,
            singleLayerName)
        ShapeFile.FeatureDictListUpdateShapeFile(
            projectFeatureDictList,
            singleLayerShapeFilePath,
            singleLayerName)
        return

    @staticmethod
    def CountyCodeToSentinel2Zone(countyCode, countyShapeFilePath, layerName=None):
        """
        依据县代码获得哨兵图幅编号
        :param countyCode:
        :param countyShapeFilePath:
        :param layerName:
        :return:
        """
        fieldDict = {"qhdm": countyCode}
        featureDictList = ShapeFile.GetShapeFileFeatureDictByField(
            fieldDict, countyShapeFilePath, layerName)
        s2ZoneList = []
        for featureDict in featureDictList:
            featureproperties = featureDict["properties"]
            s2ZoneFieldValue = featureproperties["S2Zone"]
            s2ZoneStrList = s2ZoneFieldValue.split("_")
            for s2ZoneStr in s2ZoneStrList:
                s2ZoneList.append(s2ZoneStr)
        return s2ZoneList
